home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / gfx / 3d / irit50src.lha / irit5 / prsr_lib / iritprs2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-14  |  52.3 KB  |  1,256 lines

  1. /*****************************************************************************
  2. * Generic parser for the "Irit" solid modeller.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Sep. 1991   *
  5. *****************************************************************************/
  6.  
  7. #ifdef USE_VARARGS
  8. #include <varargs.h>
  9. #else
  10. #include <stdarg.h>
  11. #endif /* USE_VARARGS */
  12.  
  13. #include <stdio.h>
  14. #include <ctype.h>
  15. #include <math.h>
  16. #include <string.h>
  17. #include <setjmp.h>
  18. #include "irit_sm.h"
  19. #include "prsr_loc.h"
  20. #include "allocate.h"
  21. #include "attribut.h"
  22. #include "irit_soc.h"
  23.  
  24. #ifdef __WINNT__
  25. #include <fcntl.h>
  26. #include <io.h>
  27. #endif /* __WINNT__ */
  28.  
  29. #define CONVEX_EPSILON        1e-3
  30. #define ZERO_NUM_EPSILON    1e-15
  31. #define NORMAL_MIN_VALID_LEN    0.03
  32.  
  33. static char
  34.     GlblTokenError[LINE_LEN_LONG];          /* Last token error was found. */
  35. static IritPrsrPrintFuncType
  36.     IritPrsrPrintFunc = NULL;
  37.  
  38. jmp_buf _IritPrsrLongJumpBuffer;           /* Used in error traping. */
  39. int _IritPrsrPolyListCirc = FALSE,
  40.     _IritPrsrGlblParserError = IP_NO_ERR,        /* Last err # found. */
  41.     _IritPrsrReadOneObject = FALSE,    /* If only one object is to be read. */
  42.     IritPrsrWasViewMat = FALSE,
  43.     IritPrsrWasPrspMat = FALSE;
  44. char
  45.     *_IPGlblFloatFormat = "%lg";
  46.  
  47. MatrixType IritPrsrViewMat = {              /* Isometric view, by default. */
  48.     { -0.707107, -0.408248, 0.577350, 0.000000 },
  49.     {  0.707107, -0.408248, 0.577350, 0.000000 },
  50.     {  0.000000,  0.816496, 0.577350, 0.000000 },
  51.     {  0.000000,  0.000000, 0.000000, 1.000000 }
  52. };
  53. MatrixType IritPrsrPrspMat = {
  54.     { 1, 0, 0, 0 },
  55.     { 0, 1, 0, 0 },
  56.     { 0, 0, 1, -0.35 },
  57.     { 0, 0, 0, 1.0 }
  58. };
  59.  
  60. static void IritPrsrPutAttributes(int Handler,
  61.                   IPAttributeStruct *Attr,
  62.                   int Indent);
  63. static void IritPrsrPutAllObjects(IPObjectStruct *PObj,
  64.                   int Handler,
  65.                   int Indent);
  66.  
  67. /*****************************************************************************
  68. * DESCRIPTION:                                                               M
  69. * Routine to update the Plane equation of the given polygon by the order     M
  70. * of the most robust three vertices of that polygon to define the normal.    M
  71. *                                                                            *
  72. * PARAMETERS:                                                                M
  73. *   PPoly:     To update its normal/plane equation.                          M
  74. *                                                                            *
  75. * RETURN VALUE:                                                              M
  76. *   void                                                                     M
  77. *                                                                            *
  78. * KEYWORDS:                                                                  M
  79. *   IritPrsrUpdatePolyPlane, files, parser                                   M
  80. *****************************************************************************/
  81. void IritPrsrUpdatePolyPlane(IPPolygonStruct *PPoly)
  82. {
  83.     int i;
  84.     RealType Len, V1[3], V2[3],
  85.     MaxLen = SQR(EPSILON);
  86.     IPVertexStruct
  87.     *VLast = NULL,
  88.     *V = PPoly -> PVertex;
  89.     PlaneType Plane;
  90.  
  91.     if (V == NULL || V -> Pnext == NULL || V -> Pnext -> Pnext == NULL)
  92.     _IPParserAbort(IP_ERR_DEGEN_POLYGON, "");
  93.  
  94.     for (i = 0; i < 4; i++)
  95.     PPoly -> Plane[i] = 0.0;
  96.  
  97.     /* Force list to be circular. Will be recovered immediately after. */
  98.     if (!_IritPrsrPolyListCirc) {
  99.     VLast = IritPrsrGetLastVrtx(V);
  100.     VLast -> Pnext = V;
  101.     }
  102.  
  103.     do {
  104.     PT_SUB(V1, V -> Coord, V -> Pnext -> Coord);
  105.     V = V -> Pnext;
  106.     PT_SUB(V2, V -> Coord, V -> Pnext -> Coord);
  107.  
  108.     Plane[0] = V1[1] * V2[2] - V2[1] * V1[2];
  109.     Plane[1] = V1[2] * V2[0] - V2[2] * V1[0];
  110.     Plane[2] = V1[0] * V2[1] - V2[0] * V1[1];
  111.  
  112.     /* Normalize the plane such that the normal has length of 1: */
  113.     Len = PT_LENGTH(Plane);
  114.     if (Len > MaxLen) {
  115.         for (i = 0; i < 3; i++)
  116.         PPoly -> Plane[i] = Plane[i] / Len;
  117.  
  118.         MaxLen = Len;
  119.  
  120.         if (MaxLen > SQR(NORMAL_MIN_VALID_LEN))
  121.             break;
  122.     }
  123.  
  124.     V = V -> Pnext;
  125.     }
  126.     while (V != PPoly -> PVertex &&
  127.        V -> Pnext != NULL &&
  128.        V -> Pnext -> Pnext != NULL);
  129.  
  130.     if (VLast != NULL) /* Recover non circular list, if was non circular. */
  131.     VLast -> Pnext = NULL;
  132.  
  133.     if (MaxLen < SQR(EPSILON))
  134.     _IPParserAbort(IP_ERR_DEGEN_NORMAL, "");
  135.  
  136.     PPoly -> Plane[3] =
  137.     -DOT_PROD(PPoly -> Plane, PPoly -> PVertex -> Coord);
  138.  
  139.     IP_SET_PLANE_POLY(PPoly);
  140. }
  141.  
  142. /*****************************************************************************
  143. * DESCRIPTION:                                                               M
  144. *   Routine to update the Plane equation of the given polygon such that the  M
  145. * Vin vertex will be in the positive side of it.                 M
  146. *                                                                            *
  147. * PARAMETERS:                                                                M
  148. *   PPoly:     To update its normal/plane equation.                          M
  149. *   Vin:       A vertex to be considered in the inside, respective to PPoly. M
  150. *                                                                            *
  151. * RETURN VALUE:                                                              M
  152. *   void                                                                     M
  153. *                                                                            *
  154. * KEYWORDS:                                                                  M
  155. *   IritPrsrUpdatePolyPlane2, files, parser                                  M
  156. *****************************************************************************/
  157. void IritPrsrUpdatePolyPlane2(IPPolygonStruct *PPoly, VectorType Vin)
  158. {
  159.     int i;
  160.  
  161.     IritPrsrUpdatePolyPlane(PPoly);
  162.  
  163.     if (DOT_PROD(PPoly -> Plane, Vin) + PPoly -> Plane[3] < 0) {
  164.     /* Flip plane normal and reverse the vertex list. */
  165.     IritPrsrReverseVrtxList(PPoly);
  166.     for (i = 0; i < 4; i++)
  167.         PPoly -> Plane[i] = (-PPoly -> Plane[i]);
  168.     }
  169. }
  170.  
  171. /*****************************************************************************
  172. * DESCRIPTION:                                                               M
  173. * Routine to update all vertices in polygon to hold a default normal if      M
  174. * have none already.                                 M
  175. *                                                                            *
  176. * PARAMETERS:                                                                M
  177. *   PPoly:       Polygon to update normal information.                       M
  178. *   DefNrml:     Normal tp use in update.                                    M
  179. *                                                                            *
  180. * RETURN VALUE:                                                              M
  181. *   void                                                                     M
  182. *                                                                            *
  183. * KEYWORDS:                                                                  M
  184. *   IritPrsrUpdateVrtxNrml, files, parser                     M
  185. *****************************************************************************/
  186. void IritPrsrUpdateVrtxNrml(IPPolygonStruct *PPoly, VectorType DefNrml)
  187. {
  188.     IPVertexStruct
  189.     *V = PPoly -> PVertex;
  190.  
  191.     do {
  192.     if (!IP_HAS_NORMAL_VRTX(V)) {
  193.         PT_COPY(V -> Normal, DefNrml);
  194.         IP_SET_NORMAL_VRTX(V);
  195.     }
  196.     V = V -> Pnext;
  197.     }
  198.     while (V != NULL && V != PPoly -> PVertex);
  199. }
  200.  
  201. /*****************************************************************************
  202. * DESCRIPTION:                                                               M
  203. * Reverses a list of objects, in place.                         M
  204. *                                                                            *
  205. * PARAMETERS:                                                                M
  206. *   PObj:      A list of objects to reverse.                                 M
  207. *                                                                            *
  208. * RETURN VALUE:                                                              M
  209. *   IPObjectStruct *:  Reverse list of objects, in place.                    M
  210. *                                                                            *
  211. * KEYWORDS:                                                                  M
  212. *   IritPrsrReverseObjList, reverse, files, parser                           M
  213. *                                                                            M
  214. *****************************************************************************/
  215. IPObjectStruct *IritPrsrReverseObjList(IPObjectStruct *PObj)
  216. {
  217.     IPObjectStruct
  218.     *NewPObjs = NULL;
  219.  
  220.     while (PObj) {
  221.     IPObjectStruct
  222.         *Pnext = PObj -> Pnext;
  223.  
  224.     PObj -> Pnext = NewPObjs;
  225.     NewPObjs = PObj;
  226.  
  227.     PObj = Pnext;
  228.     }
  229.  
  230.     return NewPObjs;
  231. }
  232.  
  233. /*****************************************************************************
  234. * DESCRIPTION:                                                               M
  235. * Reverses the vertex list of a given polygon. This is used mainly to        M
  236. * reverse polygons such that cross product of consecutive edges which form   M
  237. * a convex corner will point in the polygon normal direction.             M
  238. *                                                                            *
  239. * PARAMETERS:                                                                M
  240. *   Pl:        A polygon to reverse its vertex list, in place.               M
  241. *                                                                            *
  242. * RETURN VALUE:                                                              M
  243. *   void                                                                     M
  244. *                                                                            *
  245. * KEYWORDS:                                                                  M
  246. *   IritPrsrReverseVrtxList , reverse, files, parser                         M
  247. *****************************************************************************/
  248. void IritPrsrReverseVrtxList(IPPolygonStruct *Pl)
  249. {
  250.     ByteType Tags, Count;
  251.     IPVertexStruct *VNextNext, *VLast,
  252.     *V = Pl -> PVertex,
  253.     *VNext = V -> Pnext;
  254.  
  255.     /* Force list to be circular. Will be recovered immediately after. */
  256.     if (!_IritPrsrPolyListCirc) {
  257.     VLast = IritPrsrGetLastVrtx(V);
  258.     VLast -> Pnext = V;
  259.     }
  260.  
  261.     do {
  262.     VNextNext = VNext -> Pnext;
  263.     VNext -> Pnext = V;                 /* Reverse the pointer! */
  264.  
  265.     V = VNext;               /* Advance all 3 pointers by one. */
  266.     VNext = VNextNext;
  267.     VNextNext = VNextNext -> Pnext;
  268.     }
  269.     while (V != Pl -> PVertex);
  270.  
  271.     V = Pl -> PVertex;      /* Move the Tags/Count by one - to the right edge. */
  272.     Tags = V -> Tags;
  273.     Count = V -> Count;
  274.     do {
  275.     if (V -> Pnext == Pl -> PVertex) {
  276.         V -> Tags = Tags;
  277.         V -> Count = Count;
  278.     }
  279.     else {
  280.         V -> Tags = V -> Pnext -> Tags;
  281.         V -> Count = V -> Pnext -> Count;
  282.     }
  283.  
  284.     V = V -> Pnext;
  285.     }
  286.     while (V != Pl -> PVertex);
  287.  
  288.     /* Recover non circular list, if needs to. */
  289.     if (!_IritPrsrPolyListCirc) {
  290.     VLast = IritPrsrGetLastVrtx(Pl -> PVertex);
  291.     VLast -> Pnext = NULL;
  292.     }
  293. }
  294.  
  295. /*****************************************************************************
  296. * DESCRIPTION:                                                               M
  297. * Routine to abort parsing operation and save error reported.             M
  298. *   See also function IritPrsrParseError.                     M
  299. *                                                                            *
  300. * PARAMETERS:                                                                M
  301. *   ErrNum:   Type of error that had occured.                                M
  302. *   Msg:      A message to accompany the error number.                       M
  303. *                                                                            *
  304. * RETURN VALUE:                                                              M
  305. *   void                                                                     M
  306. *                                                                            *
  307. * KEYWORDS:                                                                  M
  308. *   _IPParserAbort, error handling, files, parser                            M
  309. *****************************************************************************/
  310. void _IPParserAbort(IritPrsrErrType ErrNum, char *Msg)
  311. {
  312.     _IritPrsrGlblParserError = ErrNum;
  313.     strcpy(GlblTokenError, Msg);    /* Keep the message in safe place... */
  314.  
  315.     longjmp(_IritPrsrLongJumpBuffer, 1);               /* Jump to... */
  316. }
  317.  
  318. /*****************************************************************************
  319. * DESCRIPTION:                                                               M
  320. * Returns TRUE if error has happend since last call to this function during  M
  321. * data read or write, FALSE otherwise.                         M
  322. *   If error, then ErrorMsg is updated to point on static str describing it. M
  323. *                                                                            *
  324. * PARAMETERS:                                                                M
  325. *   LineNum:    Line number of error, in file/stream.                         M
  326. *   ErrorMsg:   To be updated with latest error to have happened in parser.  M
  327. *                                                                            *
  328. * RETURN VALUE:                                                              M
  329. *   int:        TRUE  if error occured since last call, FALSE otherwise.     M
  330. *                                                                            *
  331. * KEYWORDS:                                                                  M
  332. *   IritPrsrParseError, error handling, files, parser                        M
  333. *****************************************************************************/
  334. int IritPrsrParseError(int LineNum, char **ErrorMsg)
  335. {
  336.     IritPrsrErrType Temp;
  337.     char TempCopy[LINE_LEN_LONG];
  338.  
  339.     if ((Temp = _IritPrsrGlblParserError) == IP_NO_ERR)
  340.     return FALSE;
  341.  
  342.     strcpy(TempCopy, GlblTokenError);
  343.     _IritPrsrGlblParserError = IP_NO_ERR;
  344.  
  345.     switch (Temp) {
  346.     case IP_ERR_NUMBER_EXPECTED:
  347.         sprintf(GlblTokenError, "Line %d: Numeric data expected - found %s",
  348.             LineNum, TempCopy);
  349.         break;
  350.     case IP_ERR_OPEN_PAREN_EXPECTED:
  351.         sprintf(GlblTokenError, "Line %d: '[' expected - found '%s'",
  352.             LineNum, TempCopy);
  353.         break;
  354.     case IP_ERR_CLOSE_PAREN_EXPECTED:
  355.         sprintf(GlblTokenError, "Line %d: ']' expected - found '%s'",
  356.             LineNum, TempCopy);
  357.         break;
  358.     case IP_ERR_LIST_COMP_UNDEF:
  359.         sprintf(GlblTokenError, "Line %d: Undefined list element - \"%s\"",
  360.             LineNum, TempCopy);
  361.         break;
  362.     case IP_ERR_UNDEF_EXPR_HEADER:
  363.         sprintf(GlblTokenError, "Line %d: Undefined TOKEN - \"%s\"",
  364.             LineNum, TempCopy);
  365.         break;
  366.     case IP_ERR_PT_TYPE_EXPECTED:
  367.         sprintf(GlblTokenError, "Line %d: Point type expected",
  368.             LineNum);
  369.         break;
  370.     case IP_ERR_OBJECT_EMPTY:
  371.         sprintf(GlblTokenError, "Line %d: Empty object found",
  372.             LineNum);
  373.         break;
  374.     case IP_ERR_FILE_EMPTY:
  375.         sprintf(GlblTokenError, "Line %d: Empty object found",
  376.             LineNum);
  377.         break;
  378.     case IP_ERR_MIXED_TYPES:
  379.         sprintf(GlblTokenError,
  380.             "Line %d: Mixed data types in same object",
  381.             LineNum);
  382.         break;
  383.     case IP_ERR_STR_NOT_IN_QUOTES:
  384.         sprintf(GlblTokenError,
  385.             "Line %d: String not in quotes (%s)",
  386.             LineNum, TempCopy);
  387.         break;
  388.     case IP_ERR_OBJECT_EXPECTED:
  389.         sprintf(GlblTokenError,
  390.             "Line %d: 'OBJECT' expected, found '%s'",
  391.             LineNum, TempCopy);
  392.         break;
  393.     case IP_ERR_CAGD_LIB_ERR:
  394.     case IP_ERR_TRIM_LIB_ERR:
  395.     case IP_ERR_TRIV_LIB_ERR:
  396.         sprintf(GlblTokenError, "Line %d: %s",
  397.             LineNum, TempCopy);
  398.         break;
  399.     case IP_ERR_STACK_OVERFLOW:
  400.         sprintf(GlblTokenError, "Line %d: Parser Stack overflow",
  401.             LineNum);
  402.         break;
  403.     case IP_ERR_DEGEN_POLYGON:
  404.         sprintf(GlblTokenError, "Line %d: Degenerate polygon",
  405.             LineNum);
  406.         break;
  407.     case IP_ERR_DEGEN_NORMAL:
  408.         sprintf(GlblTokenError, "Line %d: Degenerate normal",
  409.             LineNum);
  410.         break;
  411.     case IP_ERR_SOCKET_BROKEN:
  412.         sprintf(GlblTokenError, "Line %d: Socket connection is broken",
  413.             LineNum);
  414.         break;
  415.     case IP_ERR_SOCKET_TIME_OUT:
  416.         sprintf(GlblTokenError, "Line %d: Socket connection is broken",
  417.             LineNum);
  418.         break;
  419.     case IP_ERR_BIN_IN_TEXT:
  420.         sprintf(GlblTokenError, "Binary information in text file - %s",
  421.             TempCopy);
  422.         break;
  423.     case IP_ERR_BIN_UNDEF_OBJ:
  424.         sprintf(GlblTokenError, "Binary stream: Undefined object");
  425.         break;
  426.     default:
  427.         sprintf(GlblTokenError,
  428.             "Line %d: Data file parser - undefined error",
  429.             LineNum);
  430.         break;
  431.     }
  432.  
  433.     *ErrorMsg = GlblTokenError;
  434.  
  435.     return TRUE;
  436. }
  437.  
  438. /*****************************************************************************
  439. * DESCRIPTION:                                                               M
  440. * Routine to test if the given polygon is convex (by IRIT definition) or     M
  441. * not.                                         M
  442. *   Algorithm: The polygon is convex iff the normals generated from cross    M
  443. * products of two consecutive edges points to the same direction. The same   M
  444. * direction is tested by a positive dot product.                 M
  445. *                                                                            *
  446. * PARAMETERS:                                                                M
  447. *   Pl:         To test for convexity.                                       M
  448. *                                                                            *
  449. * RETURN VALUE:                                                              M
  450. *   int:        TRUE if PL convex, FALSE otherwise.                          M
  451. *                                                                            *
  452. * KEYWORDS:                                                                  M
  453. *   IritPrsrIsConvexPolygon, convexity, files, parser                        M
  454. *****************************************************************************/
  455. int IritPrsrIsConvexPolygon(IPPolygonStruct *Pl)
  456. {
  457.     RealType Size, V1[3], V2[3], LastNormal[3], Normal[3];
  458.     IPVertexStruct *VNext, *VNextNext,
  459.     *V = Pl -> PVertex;
  460.  
  461.     LastNormal[0] = LastNormal[1] = LastNormal[2] = 0.0;
  462.  
  463.     do {
  464.     if ((VNext = V -> Pnext) == NULL)
  465.         VNext = Pl -> PVertex;
  466.     if ((VNextNext = VNext -> Pnext) == NULL)
  467.         VNextNext = Pl -> PVertex;
  468.  
  469.     PT_SUB(V1, VNext -> Coord, V -> Coord);
  470.     if ((Size = PT_LENGTH(V1)) > EPSILON) {
  471.         Size = 1.0 / Size;
  472.         PT_SCALE(V1, Size);
  473.     }
  474.     PT_SUB(V2, VNextNext -> Coord, VNext -> Coord);
  475.     if ((Size = PT_LENGTH(V2)) > EPSILON) {
  476.         Size = 1.0 / Size;
  477.         PT_SCALE(V2, Size);
  478.     }
  479.     CROSS_PROD(Normal, V1, V2);
  480.  
  481.     if (V != Pl -> PVertex) {
  482.         if (PT_LENGTH(Normal) > CONVEX_EPSILON &&
  483.         DOT_PROD(Normal, LastNormal) < -CONVEX_EPSILON)
  484.         return FALSE;
  485.     }
  486.  
  487.     PT_COPY(LastNormal, Normal);
  488.  
  489.     V = VNext;
  490.     }
  491.     while (V != Pl -> PVertex && V != NULL);
  492.  
  493.     return TRUE;
  494. }
  495.  
  496. /*****************************************************************************
  497. * DESCRIPTION:                                                               M
  498. * Routine to print the data from given object into stdout.             M
  499. *                                                                            *
  500. * PARAMETERS:                                                                M
  501. *   PObj:      To be put out to stdout.                                      M
  502. *                                                                            *
  503. * RETURN VALUE:                                                              M
  504. *   void                                                                     M
  505. *                                                                            *
  506. * KEYWORDS:                                                                  M
  507. *   IritPrsrStdoutObject, files                                              M
  508. *****************************************************************************/
  509. void IritPrsrStdoutObject(IPObjectStruct *PObj)
  510. {
  511.     IritPrsrPutObjectToFile(stdout, PObj);
  512. }
  513.  
  514. /*****************************************************************************
  515. * DESCRIPTION:                                                               M
  516. * Routine to print the data from given object into stderr.             M
  517. *                                                                            *
  518. * PARAMETERS:                                                                M
  519. *   PObj:      To be put out to stderr.                                      M
  520. *                                                                            *
  521. * RETURN VALUE:                                                              M
  522. *   void                                                                     M
  523. *                                                                            *
  524. * KEYWORDS:                                                                  M
  525. *   IritPrsrStderrObject, files                                              M
  526. *****************************************************************************/
  527. void IritPrsrStderrObject(IPObjectStruct *PObj)
  528. {
  529.     IritPrsrPutObjectToFile(stderr, PObj);
  530. }
  531.  
  532. /*****************************************************************************
  533. * DESCRIPTION:                                                               M
  534. * Routine to print the data from given object into given file FileName.         M
  535. *   If FileName is NULL or empty, print using IritPrsrPrintFunc.         M
  536. *   See function IritPrsrSetPrintFunc, IritPrsrSetFloatFormat.             M
  537. *                                                                            *
  538. * PARAMETERS:                                                                M
  539. *   f:        Output stream.                                                 M
  540. *   PObj:     Object to put on output stream.                                M
  541. *                                                                            *
  542. * RETURN VALUE:                                                              M
  543. *   void                                                                     M
  544. *                                                                            *
  545. * KEYWORDS:                                                                  M
  546. *   IritPrsrPutObjectToFile, files                                           M
  547. *****************************************************************************/
  548. void IritPrsrPutObjectToFile(FILE *f, IPObjectStruct *PObj)
  549. {
  550.     int Handler = -1;
  551.  
  552.     /* If the following gain control and is non zero - its from error! */
  553.     if (setjmp(_IritPrsrLongJumpBuffer) != 0) {
  554.     IritPrsrCloseStream(Handler, TRUE);
  555.     return;
  556.     }
  557.  
  558.     Handler = IritPrsrOpenStreamFromFile(f, FALSE, FALSE, FALSE);
  559.  
  560.     if (f != NULL && f != stdout && f != stderr)
  561.     IRIT_DATA_HEADER(f, "Irit");
  562.  
  563.     if (_IPStream[Handler].IsBinary)
  564.         IritPrsrPutBinObject(Handler, PObj);
  565.     else
  566.     IritPrsrPutAllObjects(PObj, Handler, 0);
  567.  
  568.     IritPrsrCloseStream(Handler, TRUE);
  569. }
  570.  
  571. /*****************************************************************************
  572. * DESCRIPTION:                                                               M
  573. * Routine to print the data from given object into given file FileName.         M
  574. *   If FileName is NULL or empty, print using IritPrsrPrintFunc.         M
  575. *   See function IritPrsrSetPrintFunc, IritPrsrSetFloatFormat.            M
  576. *                                                                            *
  577. * PARAMETERS:                                                                M
  578. *   Handler:  A handler to the open stream.                     M
  579. *   PObj:     Object to put on output stream.                                M
  580. *                                                                            *
  581. * RETURN VALUE:                                                              M
  582. *   void                                                                     M
  583. *                                                                            *
  584. * KEYWORDS:                                                                  M
  585. *   IritPrsrPutObjectToHandler, files                                        M
  586. *****************************************************************************/
  587. void IritPrsrPutObjectToHandler(int Handler, IPObjectStruct *PObj)
  588. {
  589.     if (_IPStream[Handler].IsBinary)
  590.         IritPrsrPutBinObject(Handler, PObj);
  591.     else
  592.     IritPrsrPutAllObjects(PObj, Handler, 0);
  593. }
  594.  
  595. /*****************************************************************************
  596. * DESCRIPTION:                                                               *
  597. * Routine to print out the data from given object.                 *
  598. *                                                                            *
  599. * PARAMETERS:                                                                *
  600. *   PObj:      Object to put out.                                            *
  601. *   Handler:   A handler to the open stream.                     *
  602. *   Indent:    Indentation to put object at.                                 *
  603. *                                                                            *
  604. * RETURN VALUE:                                                              *
  605. *   void                                                                     *
  606. *****************************************************************************/
  607. static void IritPrsrPutAllObjects(IPObjectStruct *PObj,
  608.                   int Handler,
  609.                   int Indent)
  610. {
  611.     int i, IsRational, NumCoords;
  612.     char Str[LINE_LEN],
  613.     *ErrStr = NULL;
  614.     CagdRType *Coords;
  615.     IPObjectStruct *PObjTmp;
  616.     IPPolygonStruct *PPolygon;
  617.     IPVertexStruct *PVertex;
  618.     IPAttributeStruct
  619.     *Attr = AttrTraceAttributes(PObj -> Attrs, PObj -> Attrs);
  620.  
  621.     if (Attr) {
  622.     _IPFprintf(Handler, Indent, "[OBJECT\n");
  623.  
  624.     IritPrsrPutAttributes(Handler, Attr, Indent);
  625.  
  626.     _IPFprintf(Handler, Indent + 4,
  627.          "%s\n", strlen(PObj -> Name) ? PObj -> Name : "NONE");
  628.     }
  629.     else {
  630.     _IPFprintf(Handler, Indent, "[OBJECT %s\n",
  631.              strlen(PObj -> Name) ? PObj -> Name : "NONE");
  632.     }
  633.     Indent += 4;
  634.  
  635.     switch (PObj -> ObjType) {
  636.     case IP_OBJ_POLY:
  637.         for (PPolygon = PObj -> U.Pl;
  638.          PPolygon != NULL;
  639.          PPolygon = PPolygon -> Pnext) {
  640.         if (PPolygon -> PVertex == NULL)
  641.             continue;
  642.  
  643.         if (IP_IS_POLYLINE_OBJ(PObj))
  644.             _IPFprintf(Handler, Indent, "[POLYLINE ");
  645.         else if (IP_IS_POINTLIST_OBJ(PObj))
  646.             _IPFprintf(Handler, Indent, "[POINTLIST ");
  647.         else
  648.             _IPFprintf(Handler,
  649.             Indent, "[POLYGON [PLANE %s %s %s %s] ",
  650.             _IPReal2Str(PPolygon -> Plane[0]),
  651.             _IPReal2Str(PPolygon -> Plane[1]),
  652.             _IPReal2Str(PPolygon -> Plane[2]),
  653.             _IPReal2Str(PPolygon -> Plane[3]));
  654.  
  655.         IritPrsrPutAttributes(Handler, PPolygon -> Attrs, Indent);
  656.  
  657.         for (PVertex = PPolygon -> PVertex -> Pnext, i = 1;
  658.              PVertex != PPolygon -> PVertex && PVertex != NULL;
  659.              PVertex = PVertex -> Pnext, i++);
  660.         _IPFprintf(Handler, Indent + 4, "%d\n", i);
  661.  
  662.         PVertex = PPolygon -> PVertex;
  663.         do {             /* Assume at least one edge in polygon! */
  664.             _IPFprintf(Handler, Indent + 4, "[");
  665.             
  666.             IritPrsrPutAttributes(Handler, PVertex -> Attrs, Indent);
  667.  
  668.             if (IP_IS_POLYLINE_OBJ(PObj) ||
  669.             (IP_IS_POLYGON_OBJ(PObj) &&
  670.              PT_APX_EQ(PPolygon -> Plane, PVertex -> Normal)))
  671.             _IPFprintf(Handler, 0, "%s%s %s %s]\n",
  672.                 IP_IS_INTERNAL_VRTX(PVertex) ? "[INTERNAL] " : "",
  673.                 _IPReal2Str(PVertex -> Coord[0]),
  674.                 _IPReal2Str(PVertex -> Coord[1]),
  675.                 _IPReal2Str(PVertex -> Coord[2]));
  676.             else if (IP_IS_POINTLIST_OBJ(PObj))
  677.             _IPFprintf(Handler, 0, "%s %s %s]\n",
  678.                 _IPReal2Str(PVertex -> Coord[0]),
  679.                 _IPReal2Str(PVertex -> Coord[1]),
  680.                 _IPReal2Str(PVertex -> Coord[2]));
  681.             else
  682.             _IPFprintf(Handler, 0,
  683.                 "%s[NORMAL %s %s %s] %s %s %s]\n",
  684.                 IP_IS_INTERNAL_VRTX(PVertex) ? "[INTERNAL] " : "",
  685.                 _IPReal2Str(PVertex -> Normal[0]),
  686.                 _IPReal2Str(PVertex -> Normal[1]),
  687.                 _IPReal2Str(PVertex -> Normal[2]),
  688.                 _IPReal2Str(PVertex -> Coord[0]),
  689.                 _IPReal2Str(PVertex -> Coord[1]),
  690.                 _IPReal2Str(PVertex -> Coord[2]));
  691.  
  692.             PVertex = PVertex -> Pnext;
  693.         }
  694.         while (PVertex != PPolygon -> PVertex && PVertex != NULL);
  695.         _IPFprintf(Handler, Indent, "]\n");    /* Close the polygon. */
  696.         }
  697.         break;
  698.     case IP_OBJ_NUMERIC:
  699.         _IPFprintf(Handler, Indent, "[NUMBER %s]\n",
  700.                _IPReal2Str(PObj -> U.R));
  701.         break;
  702.     case IP_OBJ_POINT:
  703.         _IPFprintf(Handler, Indent, "[POINT %s %s %s]\n",
  704.              _IPReal2Str(PObj -> U.Pt[0]),
  705.              _IPReal2Str(PObj -> U.Pt[1]),
  706.              _IPReal2Str(PObj -> U.Pt[2]));
  707.         break;
  708.     case IP_OBJ_VECTOR:
  709.         _IPFprintf(Handler, Indent, "[VECTOR %s %s %s]\n",
  710.              _IPReal2Str(PObj -> U.Vec[0]),
  711.              _IPReal2Str(PObj -> U.Vec[1]),
  712.              _IPReal2Str(PObj -> U.Vec[2]));
  713.         break;
  714.     case IP_OBJ_PLANE:
  715.         _IPFprintf(Handler, Indent, "[PLANE %s %s %s %s]\n",
  716.              _IPReal2Str(PObj -> U.Plane[0]),
  717.              _IPReal2Str(PObj -> U.Plane[1]),
  718.              _IPReal2Str(PObj -> U.Plane[2]),
  719.              _IPReal2Str(PObj -> U.Plane[3]));
  720.         break;
  721.     case IP_OBJ_CTLPT:
  722.         Coords = PObj -> U.CtlPt.Coords;
  723.         IsRational = CAGD_IS_RATIONAL_PT(PObj -> U.CtlPt.PtType);
  724.         NumCoords = CAGD_NUM_OF_PT_COORD(PObj -> U.CtlPt.PtType);
  725.  
  726.         sprintf(Str, "[CTLPT %c%d %s", IsRational ? 'P' : 'E', NumCoords,
  727.             IsRational ? _IPReal2Str(Coords[0]) : "");
  728.         
  729.         for (i = 1; i <= NumCoords; i++) {
  730.         strcat(Str, " ");
  731.             strcat(Str, _IPReal2Str(Coords[i]));
  732.         }
  733.         strcat(Str,"]\n");
  734.         _IPFprintf(Handler, Indent, Str);
  735.         break;
  736.     case IP_OBJ_MATRIX:
  737.         _IPFprintf(Handler, Indent, "[MATRIX\n");
  738.         for (i = 0; i < 4; i++)
  739.         _IPFprintf(Handler, Indent + 8, "%s %s %s %s%s\n",
  740.              _IPReal2Str((*PObj -> U.Mat)[i][0]),
  741.              _IPReal2Str((*PObj -> U.Mat)[i][1]),
  742.              _IPReal2Str((*PObj -> U.Mat)[i][2]),
  743.              _IPReal2Str((*PObj -> U.Mat)[i][3]),
  744.              i == 3 ? "]" : "");
  745.         break;
  746.     case IP_OBJ_STRING:
  747.         _IPFprintf(Handler, Indent, "[STRING \"%s\"]\n", PObj -> U.Str);
  748.         break;
  749.     case IP_OBJ_LIST_OBJ:
  750.         for (i = 0; (PObjTmp = ListObjectGet(PObj, i)) != NULL; i++)
  751.         IritPrsrPutAllObjects(PObjTmp, Handler, Indent);
  752.         break;
  753.     case IP_OBJ_CURVE:
  754.             CagdCrvWriteToFile2(PObj -> U.Crvs, Handler,
  755.                 Indent, NULL, &ErrStr);
  756.         if (ErrStr != NULL)
  757.         _IPParserAbort(IP_ERR_CAGD_LIB_ERR, ErrStr);
  758.         break;
  759.     case IP_OBJ_SURFACE:
  760.         CagdSrfWriteToFile2(PObj -> U.Srfs, Handler,
  761.                 Indent, NULL, &ErrStr);
  762.         if (ErrStr != NULL)
  763.         _IPParserAbort(IP_ERR_CAGD_LIB_ERR, ErrStr);
  764.         break;
  765.     case IP_OBJ_TRIMSRF:
  766.         TrimWriteTrimmedSrfToFile2(PObj -> U.TrimSrfs, Handler,
  767.                        Indent, NULL, &ErrStr);
  768.         if (ErrStr != NULL)
  769.         _IPParserAbort(IP_ERR_TRIM_LIB_ERR, ErrStr);
  770.         break;
  771.     case IP_OBJ_TRIVAR:
  772.         TrivTVWriteToFile2(PObj -> U.Trivars, Handler,
  773.                    Indent, NULL, &ErrStr);
  774.         if (ErrStr != NULL)
  775.         _IPParserAbort(IP_ERR_TRIV_LIB_ERR, ErrStr);
  776.         break;
  777.     default:
  778.         IritPrsrFatalError("Attemp to print undefine object type.");
  779.         break;
  780.     }
  781.  
  782.     Indent -= 4;
  783.     _IPFprintf(Handler, Indent, "]\n");            /* Close the object. */
  784. }
  785.  
  786. /*****************************************************************************
  787. * DESCRIPTION:                                                               *
  788. * Same as fprintf but with indentation.                         *
  789. *   See function IritPrsrSetPrintFunc, IritPrsrSetFloatFormat             *
  790. *                                                                            *
  791. * PARAMETERS:                                                                *
  792. *   Handler:    A handler to the open stream.                     *
  793. *   Indent:     All printing will start at this column.                      *
  794. *   va_alist:   Do "man stdarg"                                              *
  795. *                                                                            *
  796. * RETURN VALUE:                                                              *
  797. *   void                                                                     *
  798. *****************************************************************************/
  799. #ifdef USE_VARARGS
  800. void _IPFprintf(int Handler, int Indent, char *va_alist, ...)
  801. {
  802.     char *Format, Line[LINE_LEN_LONG];
  803.     int i;
  804.     va_list ArgPtr;
  805.  
  806.     va_start(ArgPtr);
  807.     Format = va_arg(ArgPtr, char *);
  808. #else
  809. void _IPFprintf(int Handler, int Indent, char *Format, ...)
  810. {
  811.     char Line[LINE_LEN_LONG];
  812.     int i;
  813.     va_list ArgPtr;
  814.  
  815.     va_start(ArgPtr, Format);
  816. #endif /* USE_VARARGS */
  817.  
  818.     if (IritPrsrPrintFunc != NULL || _IPStream[Handler].f != NULL) {
  819.     for (i = 0; Indent >= 8; i++, Indent -= 8)
  820.         Line[i] = '\t';
  821.     while (Indent--)
  822.         Line[i++] = ' ';
  823.     vsprintf(&Line[i], Format, ArgPtr);
  824.  
  825.     if (_IPStream[Handler].f != NULL)
  826.         fprintf(_IPStream[Handler].f, Line);
  827.     else
  828.         IritPrsrPrintFunc(Line);
  829.     }
  830.     else {     /* _IPStream[Handler].f == NULL and it is a socket connction. */
  831.     /* No need for indentation if writing to a socket. */
  832.     vsprintf(Line, Format, ArgPtr);
  833.     SocWriteLine(Handler, Line, strlen(Line));
  834.     }
  835.  
  836.     va_end(ArgPtr);
  837. }
  838.  
  839. /*****************************************************************************
  840. * DESCRIPTION:                                                               *
  841. * Routine to print the attributes of given attribute list.             *
  842. *                                                                            *
  843. * PARAMETERS:                                                                *
  844. *   Handler:    A handler to the open stream.                     *
  845. *   Attr:     Attributes to put out.                                         *
  846. *   Indent:   Indentation to put attributes at.                              *
  847. *                                                                            *
  848. * RETURN VALUE:                                                              *
  849. *   void                                                                     *
  850. *****************************************************************************/
  851. static void IritPrsrPutAttributes(int Handler,
  852.                   IPAttributeStruct *Attr,
  853.                   int Indent)
  854. {
  855.     Attr = AttrTraceAttributes(Attr, Attr);
  856.  
  857.     while (Attr) {
  858.     if (Attr -> Type == IP_ATTR_OBJ) {
  859.         _IPFprintf(Handler, Indent + 4, "[%s\n", Attr -> Name);
  860.         IritPrsrPutAllObjects(Attr -> U.PObj, Handler, Indent + 8);
  861.         _IPFprintf(Handler, Indent + 4, "]\n");
  862.     }
  863.     else 
  864.         _IPFprintf(Handler, Indent + 4, "%s\n", Attr2String(Attr));
  865.  
  866.     Attr = AttrTraceAttributes(Attr, NULL);
  867.     }
  868. }
  869.  
  870. /*****************************************************************************
  871. * DESCRIPTION:                                                               *
  872. * Convert a real number into a string.                         *
  873. *   The routine maintains six different buffers simultanuously so up to six  *
  874. * consecutive calls can be issued from same printf and stiil have valid      *
  875. * strings.                                     *
  876. *                                                                            *
  877. * PARAMETERS:                                                                *
  878. *   R:        A  real number to convert to a string.                         *
  879. *                                                                            *
  880. * RETURN VALUE:                                                              *
  881. *   char *:   A string representing R.                                       *
  882. *****************************************************************************/
  883. char *_IPReal2Str(RealType R)
  884. {
  885.     static int j, k,
  886.     i = 0;
  887.     static char Buffer[6][LINE_LEN_SHORT], Line[LINE_LEN];
  888.  
  889.     if (ABS(R) < ZERO_NUM_EPSILON)
  890.     R = 0.0;                /* Round off very small numbers. */
  891.  
  892.     sprintf(Buffer[i], _IPGlblFloatFormat, R);
  893.  
  894.     for (k = 0; !isdigit(Buffer[i][k]) && k < LINE_LEN; k++);
  895.     if (k >= LINE_LEN) {
  896.     sprintf(Line, "Conversion of real number (%f) failed.", R);
  897.     IritPrsrFatalError(Line);
  898.     }
  899.  
  900.     for (j = strlen(Buffer[i]) - 1; Buffer[i][j] == ' ' && j > k; j--);
  901.     if (strchr(Buffer[i], '.') != NULL &&
  902.     strchr(Buffer[i], 'e') == NULL &&
  903.     strchr(Buffer[i], 'E') == NULL)
  904.     for (; Buffer[i][j] == '0' && j > k; j--);
  905.     Buffer[i][j + 1] = 0;
  906.  
  907.     j = i;
  908.     i = (i + 1) % 6;
  909.     return Buffer[j];
  910. }
  911.  
  912. /*****************************************************************************
  913. * DESCRIPTION:                                                               M
  914. * Returns a pointer to last vertex of a list.                     M
  915. *                                                                            *
  916. * PARAMETERS:                                                                M
  917. *   VList:    A list of vertices                                             M
  918. *                                                                            *
  919. * RETURN VALUE:                                                              M
  920. *   IPVertexStruct *:    Last vertex in VList.                               M
  921. *                                                                            *
  922. * KEYWORDS:                                                                  M
  923. *   IritPrsrGetLastVrtx, linked lists, last element                          M
  924. *****************************************************************************/
  925. IPVertexStruct *IritPrsrGetLastVrtx(IPVertexStruct *VList)
  926. {
  927.     return IritPrsrGetPrevVrtx(VList, NULL);
  928. }
  929.  
  930. /*****************************************************************************
  931. * DESCRIPTION:                                                               M
  932. * Returns a pointer to previous vertex in VList to V.                 M
  933. *                                                                            *
  934. * PARAMETERS:                                                                M
  935. *   VList:    A list of vertices.                                            M
  936. *   V:        For which the previous vertex in VList is pursuit.             M
  937. *                                                                            *
  938. * RETURN VALUE:                                                              M
  939. *   IPVertexStruct *:   Previous vertex to V in VList if found, NULL         M
  940. *                       otherwise.                                           M
  941. *                                                                            *
  942. * KEYWORDS:                                                                  M
  943. *   IritPrsrGetPrevVrtx, previous element, linked lists                      M
  944. *****************************************************************************/
  945. IPVertexStruct *IritPrsrGetPrevVrtx(IPVertexStruct *VList, IPVertexStruct *V)
  946. {
  947.     IPVertexStruct
  948.     *VHead = VList;
  949.  
  950.     if (VList == NULL || VList == V)
  951.     return NULL;
  952.  
  953.     for ( ;
  954.       VList != NULL && VList -> Pnext != V && VList -> Pnext != VHead;
  955.       VList = VList -> Pnext);
  956.  
  957.     return VList;
  958. }
  959.  
  960. /*****************************************************************************
  961. * DESCRIPTION:                                                               M
  962. * Appends two vertex lists together.                              M
  963. *                                                                            *
  964. * PARAMETERS:                                                                M
  965. *   VList1, VList2:  Two lists to append.                                    M
  966. *                                                                            *
  967. * RETURN VALUE:                                                              M
  968. *   IPVertexStruct *:    Appended list.                                     M
  969. *                                                                            *
  970. * KEYWORDS:                                                                  M
  971. *   IritPrsrAppendVrtxLists, linked lists                                    M
  972. *****************************************************************************/
  973. IPVertexStruct *IritPrsrAppendVrtxLists(IPVertexStruct *VList1,
  974.                     IPVertexStruct *VList2)
  975. {
  976.     if (VList1 == NULL)
  977.         return VList2;
  978.     else if (VList2 == NULL)
  979.         return VList1;
  980.     else {
  981.     IPVertexStruct
  982.         *VLast = IritPrsrGetLastVrtx(VList1);
  983.  
  984.     VLast -> Pnext = VList2;
  985.  
  986.     return VList1;
  987.     }
  988. }
  989.  
  990. /*****************************************************************************
  991. * DESCRIPTION:                                                               M
  992. * Returns a pointer to last polygon/line of a list.                 M
  993. *                                                                            *
  994. * PARAMETERS:                                                                M
  995. *   PList:    A list of polygons.                                            M
  996. *                                                                            *
  997. * RETURN VALUE:                                                              M
  998. *   IPPolygonStruct *:    Last polygon in list PList.                        M
  999. *                                                                            *
  1000. * KEYWORDS:                                                                  M
  1001. *   IritPrsrGetLastPoly, linked lists, last element                          M
  1002. *****************************************************************************/
  1003. IPPolygonStruct *IritPrsrGetLastPoly(IPPolygonStruct *PList)
  1004. {
  1005.     return IritPrsrGetPrevPoly(PList, NULL);
  1006. }
  1007.  
  1008. /*****************************************************************************
  1009. * DESCRIPTION:                                                               M
  1010. * Returns a pointer to previous polygon in PList to P.                 M
  1011. *                                                                            *
  1012. * PARAMETERS:                                                                M
  1013. *   PList:    A list of polygons.                                            M
  1014. *   P:        For which the previous polygon in PList is pursuit.            M
  1015. *                                                                            *
  1016. * RETURN VALUE:                                                              M
  1017. *   IPVertexStruct *:   Previous polygon to P in PList if found, NULL        M
  1018. *                       otherwise.                                           M
  1019. *                                                                            *
  1020. * KEYWORDS:                                                                  M
  1021. *   IritPrsrGetPrevPoly, previous element, linked lists                      M
  1022. *****************************************************************************/
  1023. IPPolygonStruct *IritPrsrGetPrevPoly(IPPolygonStruct *PList,
  1024.                      IPPolygonStruct *P)
  1025. {
  1026.     if (PList == NULL || PList == P)
  1027.     return NULL;
  1028.  
  1029.     for ( ; PList != NULL && PList -> Pnext != P; PList = PList -> Pnext);
  1030.  
  1031.     return PList;
  1032. }
  1033.  
  1034. /*****************************************************************************
  1035. * DESCRIPTION:                                                               M
  1036. * Appends two poly lists together.                              M
  1037. *                                                                            *
  1038. * PARAMETERS:                                                                M
  1039. *   PList1, PList2:  Two lists to append.                                    M
  1040. *                                                                            *
  1041. * RETURN VALUE:                                                              M
  1042. *   IPPolygonStruct *:    Appended list.                                     M
  1043. *                                                                            *
  1044. * KEYWORDS:                                                                  M
  1045. *   IritPrsrAppendPolyLists, linked lists                                    M
  1046. *****************************************************************************/
  1047. IPPolygonStruct *IritPrsrAppendPolyLists(IPPolygonStruct *PList1,
  1048.                      IPPolygonStruct *PList2)
  1049. {
  1050.     if (PList1 == NULL)
  1051.         return PList2;
  1052.     else if (PList2 == NULL)
  1053.         return PList1;
  1054.     else {
  1055.     IPPolygonStruct
  1056.         *PLast = IritPrsrGetLastPoly(PList1);
  1057.  
  1058.     PLast -> Pnext = PList2;
  1059.  
  1060.     return PList1;
  1061.     }
  1062. }
  1063.  
  1064. /*****************************************************************************
  1065. * DESCRIPTION:                                                               M
  1066. * Returns a pointer to last object of a list.                     M
  1067. *                                                                            *
  1068. * PARAMETERS:                                                                M
  1069. *   OList:    A list of objects.                                             M
  1070. *                                                                            *
  1071. * RETURN VALUE:                                                              M
  1072. *   IPPolygonStruct *:    Last object in list OList.                         M
  1073. *                                                                            *
  1074. * KEYWORDS:                                                                  M
  1075. *   IritPrsrGetLastObj, linked lists, last element                           M
  1076. *****************************************************************************/
  1077. IPObjectStruct *IritPrsrGetLastObj(IPObjectStruct *OList)
  1078. {
  1079.     return IritPrsrGetPrevObj(OList, NULL);
  1080. }
  1081.  
  1082. /*****************************************************************************
  1083. * DESCRIPTION:                                                               M
  1084. * Returns a pointer to previous object in OList to O.                 M
  1085. *                                                                            *
  1086. * PARAMETERS:                                                                M
  1087. *   OList:    A list of objects.                                             M
  1088. *   O:        For which the previous object in OList is pursuit.             M
  1089. *                                                                            *
  1090. * RETURN VALUE:                                                              M
  1091. *   IPVertexStruct *:   Previous object to O in OList if found, NULL         M
  1092. *                       otherwise.                                           M
  1093. *                                                                            *
  1094. * KEYWORDS:                                                                  M
  1095. *   IritPrsrGetPrevObj, previous element, linked lists                       M
  1096. *****************************************************************************/
  1097. IPObjectStruct *IritPrsrGetPrevObj(IPObjectStruct *OList, IPObjectStruct *O)
  1098. {
  1099.     if (OList == NULL || OList == O)
  1100.     return NULL;
  1101.  
  1102.     for ( ; OList != NULL && OList -> Pnext != O; OList = OList -> Pnext);
  1103.     if (OList == NULL)
  1104.         return NULL;
  1105.  
  1106.     return OList;
  1107. }
  1108.  
  1109. /*****************************************************************************
  1110. * DESCRIPTION:                                                               M
  1111. * Appends two object lists together.                               M
  1112. *                                                                            *
  1113. * PARAMETERS:                                                                M
  1114. *   OList1, OList2:  Two lists to append.                                    M
  1115. *                                                                            *
  1116. * RETURN VALUE:                                                              M
  1117. *   IPPolygonStruct *:    Appended list.                                     M
  1118. *                                                                            *
  1119. * KEYWORDS:                                                                  M
  1120. *   IritPrsrAppendObjLists, linked lists                                     M
  1121. *****************************************************************************/
  1122. IPObjectStruct *IritPrsrAppendObjLists(IPObjectStruct *OList1,
  1123.                        IPObjectStruct *OList2)
  1124. {
  1125.     if (OList1 == NULL)
  1126.         return OList2;
  1127.     else if (OList2 == NULL)
  1128.         return OList1;
  1129.     else {
  1130.     IPObjectStruct
  1131.         *OLast = IritPrsrGetLastObj(OList1);
  1132.  
  1133.     OLast -> Pnext = OList2;
  1134.  
  1135.     return OList1;
  1136.     }
  1137. }
  1138.  
  1139. /*****************************************************************************
  1140. * DESCRIPTION:                                                               M
  1141. * Returns the length of a list of vertices.                     M
  1142. *                                                                            *
  1143. * PARAMETERS:                                                                M
  1144. *   V:        Vertex list to compute its length.                             M
  1145. *                                                                            *
  1146. * RETURN VALUE:                                                              M
  1147. *   int:      Number of elements in V list.                                  M
  1148. *                                                                            *
  1149. * KEYWORDS:                                                                  M
  1150. *   IritPrsrVrtxListLen, length, linked lists                                M
  1151. *****************************************************************************/
  1152. int IritPrsrVrtxListLen(IPVertexStruct *V)
  1153. {
  1154.     int i;
  1155.  
  1156.     for (i = 0; V != NULL; i++, V = V -> Pnext);
  1157.  
  1158.     return i;
  1159. }
  1160.  
  1161. /*****************************************************************************
  1162. * DESCRIPTION:                                                               M
  1163. * Returns the length of a list of polygons.                      M
  1164. *                                                                            *
  1165. * PARAMETERS:                                                                M
  1166. *   P:        Polygon list to compute its length.                            M
  1167. *                                                                            *
  1168. * RETURN VALUE:                                                              M
  1169. *   int:      Number of elements in P list.                                  M
  1170. *                                                                            *
  1171. * KEYWORDS:                                                                  M
  1172. *   IritPrsrPolyListLen, length, linked lists                                M
  1173. *****************************************************************************/
  1174. int IritPrsrPolyListLen(IPPolygonStruct *P)
  1175. {
  1176.     int i;
  1177.  
  1178.     for (i = 0; P != NULL; i++, P = P -> Pnext);
  1179.  
  1180.     return i;
  1181. }
  1182.  
  1183. /*****************************************************************************
  1184. * DESCRIPTION:                                                               M
  1185. * Returns the length of a list of objects.                      M
  1186. *                                                                            *
  1187. * PARAMETERS:                                                                M
  1188. *   O:        Object list to compute its length.                             M
  1189. *                                                                            *
  1190. * RETURN VALUE:                                                              M
  1191. *   int:      Number of elements in O list.                                  M
  1192. *                                                                            *
  1193. * KEYWORDS:                                                                  M
  1194. *   IritPrsrObjListLen, length, linked lists                                 M
  1195. *****************************************************************************/
  1196. int IritPrsrObjListLen(IPObjectStruct *O)
  1197. {
  1198.     int i;
  1199.  
  1200.     for (i = 0; O != NULL; i++, O = O -> Pnext);
  1201.  
  1202.     return i;
  1203. }
  1204.  
  1205. /*****************************************************************************
  1206. * DESCRIPTION:                                                               M
  1207. * Sets the printing function to call if needs to redirect printing.          M
  1208. *                                                                            *
  1209. * PARAMETERS:                                                                M
  1210. *   PrintFunc:   A function that gets a single string it should print.       M
  1211. *                                                                            *
  1212. * RETURN VALUE:                                                              M
  1213. *   void                                                                     M
  1214. *                                                                            *
  1215. * KEYWORDS:                                                                  M
  1216. *   IritPrsrSetPrintFunc, files                                              M
  1217. *****************************************************************************/
  1218. void IritPrsrSetPrintFunc(IritPrsrPrintFuncType PrintFunc)
  1219. {
  1220.     IritPrsrPrintFunc = PrintFunc;
  1221. }
  1222.  
  1223. /*****************************************************************************
  1224. * DESCRIPTION:                                                               M
  1225. * Sets the floating point printing format.                                   M
  1226. *                                                                            *
  1227. * PARAMETERS:                                                                M
  1228. *   FloatFormat:    A printf style floating point printing format string.    M
  1229. *                                                                            *
  1230. * RETURN VALUE:                                                              M
  1231. *   void                                                                     M
  1232. *                                                                            *
  1233. * KEYWORDS:                                                                  M
  1234. *   IritPrsrSetFloatFormat, files                                            M
  1235. *****************************************************************************/
  1236. void IritPrsrSetFloatFormat(char *FloatFormat)
  1237. {
  1238.     char Str[LINE_LEN];
  1239.  
  1240.     /* Not a full-proof test but something. */
  1241.     if (strlen(FloatFormat) >= 2 &&
  1242.     strchr(FloatFormat, '%') != NULL &&
  1243.     (strchr(FloatFormat, 'e') != NULL ||
  1244.      strchr(FloatFormat, 'f') != NULL ||
  1245.      strchr(FloatFormat, 'g') != NULL ||
  1246.      strchr(FloatFormat, 'E') != NULL ||
  1247.      strchr(FloatFormat, 'F') != NULL ||
  1248.      strchr(FloatFormat, 'G') != NULL)) {
  1249.     _IPGlblFloatFormat = FloatFormat;
  1250.     }
  1251.     else {
  1252.     sprintf(Str, "Illegal floating point format \"%s\".", FloatFormat);
  1253.     IritPrsrFatalError(Str);
  1254.     }    
  1255. }
  1256.